;( function ( $ ){
    $.fn.addBack = $.fn.addBack || $.fn.andSelf;

    $.fn.extend({

        actual : function ( method, options ){
            // check if the jQuery method exist
            if( !this[ method ]){
                throw '$.actual => The jQuery method "' + method + '" you called does not exist';
            }

            var defaults = {
                absolute      : false,
                clone         : false,
                includeMargin : false
            };

            var configs = $.extend( defaults, options );

            var $target = this.eq( 0 );
            var fix, restore;

            if( configs.clone === true ){
                fix = function (){
                    var style = 'position: absolute !important; top: -1000 !important; ';

                    // this is useful with css3pie
                    $target = $target.
                    clone().
                    attr( 'style', style ).
                    appendTo( 'body' );
                };

                restore = function (){
                    // remove DOM element after getting the width
                    $target.remove();
                };
            }else{
                var tmp   = [];
                var style = '';
                var $hidden;

                fix = function (){
                    // get all hidden parents
                    $hidden = $target.parents().addBack().filter( ':hidden' );
                    style   += 'visibility: hidden !important; display: block !important; ';

                    if( configs.absolute === true ) style += 'position: absolute !important; ';

                    // save the origin style props
                    // set the hidden el css to be got the actual value later
                    $hidden.each( function (){
                        var $this = $( this );

                        // Save original style. If no style was set, attr() returns undefined
                        tmp.push( $this.attr( 'style' ));
                        $this.attr( 'style', style );
                    });
                };

                restore = function (){
                    // restore origin style values
                    $hidden.each( function ( i ){
                        var $this = $( this );
                        var _tmp  = tmp[ i ];

                        if( _tmp === undefined ){
                            $this.removeAttr( 'style' );
                        }else{
                            $this.attr( 'style', _tmp );
                        }
                    });
                };
            }

            fix();
            // get the actual value with user specific methed
            // it can be 'width', 'height', 'outerWidth', 'innerWidth'... etc
            // configs.includeMargin only works for 'outerWidth' and 'outerHeight'
            var actual = /(outer)/.test( method ) ?
                $target[ method ]( configs.includeMargin ) :
                $target[ method ]();

            restore();
            // IMPORTANT, this plugin only return the value of the first element
            return actual;
        }
    });
})( jQuery );